Hi Jean-Baptiste,

We are using the following datasource factory:

admin@root()> bundle:services -p 265

OPS4J Pax JDBC Oracle Driver Adapter (265) provides:
----------------------------------------------------
objectClass = [org.osgi.service.jdbc.DataSourceFactory]
osgi.jdbc.driver.class = oracle.jdbc.OracleDriver
osgi.jdbc.driver.name = oracle
service.bundleid = 265
service.id = 300
service.scope = singleton

From that we then create an xa and a local datasource, using our own component 
rather than pax jdbc config:

admin@root()> bundle:services -p 313

xxx-withheld-xxx (313) provides:
----
eig.datasource.dialect = org.hibernate.dialect.Oracle10gDialect
eig.datasource.id = events
eig.datasource.pool.connectionTimeout = 30000
eig.datasource.pool.maxLifetime = 1800000
eig.datasource.pool.maxPoolSize = 40
eig.datasource.type = ORACLE
eig.datasource.url = xxx-withheld-xxx
eig.datasource.user = xxx-withheld-xxx
objectClass = [javax.sql.DataSource]
service.bundleid = 313
service.id = 574
service.scope = singleton
----
eig.datasource.dialect = org.hibernate.dialect.Oracle10gDialect
eig.datasource.id = events
eig.datasource.pool.connectionTimeout = 30000
eig.datasource.pool.maxLifetime = 1800000
eig.datasource.pool.maxPoolSize = 40
eig.datasource.type = ORACLE
eig.datasource.url = xxx-withheld-xxx
eig.datasource.user = xxx-withheld-xxx
objectClass = [javax.sql.XADataSource]
service.bundleid = 313
service.id = 575
service.scope = singleton

Interestingly, I took Paul up on his suggestion to use the xa datasource - and 
therefore also the xa JPAEntityManagerProviderFactory and TransactionControl 
too – and that resolved the issue!

However it’s not really a solution for us. Firstly due to performance reasons 
we require local transactions for some use cases and xa for others, so we don’t 
have the option to use xa everywhere.

And secondly in order for xa transactions to work we had to temporarily disable 
the karaf 4.4.3 eclipselink feature otherwise we get the following exception 
when obtaining an EntityManager via the 
org.osgi.service.transaction.control.JPAEntityManagerProvider.getResource() 
method:

Caused by: java.lang.NoSuchMethodError: 
org.osgi.service.jpa.EntityManagerFactoryBuilder.getPersistenceProviderName()Ljava/lang/String;
      at 
org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl.setupTransactionManager(JPAEntityManagerProviderFactoryImpl.java:250)
 ~[?:?

      at 
org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl.getProviderFor(JPAEntityManagerProviderFactoryImpl.java:220)
 ~[?:?]
      at 
org.apache.aries.tx.control.jpa.xa.impl.JPAEntityManagerProviderFactoryImpl.lambda$handleNormalDataSource$5(JPAEntityManagerProviderFactoryImpl.java:20

      at 
org.apache.aries.tx.control.jpa.common.impl.DelayedJPAEntityManagerProvider.getResource(DelayedJPAEntityManagerProvider.java:56)
 ~[?:?]
      at 
org.apache.aries.tx.control.jpa.common.impl.DelayedJPAEntityManagerProvider.getResource(DelayedJPAEntityManagerProvider.java:28)
 ~[?:?]

We tracked this down to a defective 
org.osgi.service.jpa.EntityManagerFactoryBuilder being installed via the 
eclipselink feature as declared in the official karaf 
enterprise-4.4.3-features.xml file – the javax.persistence bundle in particular:

    <feature name="eclipselink" description="Eclipselink JPA persistence engine 
support" version="2.7.11">
        <details>Eclipselink persistence engine.</details>
        <feature version="[2,3)">jpa</feature>
        <bundle 
dependency="true">mvn:org.eclipse.persistence/javax.persistence/2.2.0</bundle>
        <feature version="[2,3)">transaction</feature>
        
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.jpa/2.7.11</bundle>
        
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.core/2.7.11</bundle>
        
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.asm/9.3.0</bundle>
        
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.antlr/2.7.11</bundle>
        
<bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.jpa.jpql/2.7.11</bundle>
        
<bundle>mvn:org.apache.aries.jpa/org.apache.aries.jpa.eclipselink.adapter/2.7.3</bundle>
        <capability>
            
osgi.service;objectClass=javax.persistence.spi.PersistenceProvider;effective:=active;javax.persistence.provider=org.eclipse.persistence.jpa.PersistenceProvider
        </capability>
    </feature>

I’m using the word “defective” because the EntityManagerFactoryBuilder is 
indeed missing the getPersistenceProviderName() method even though it exports 
the package as version 1.1.0 – whereas I believe the method should exist from 
that version onwards. From the bundle manifest:

Export-Package: javax.persistence;jpa="2.2";version="2.2.0",javax.pers
istence.criteria;jpa="2.2";version="2.2.0",javax.persistence.metamode
l;jpa="2.2";version="2.2.0",javax.persistence.spi;jpa="2.2";version="
2.2.0",org.osgi.service.jpa;version="1.1.0"

We’ve no idea how to prevent the org.osgi.service.jpa package from the 
javax.persistence bundle from being imported into other bundles in preference 
to the same package from bundles (that contain the EntityManagerFactoryBuilder 
with the getPersistenceProviderName() method). For example these bundle contain 
the correct class:

admin@root()> bundle:find-class org.osgi.service.jpa.EntityManagerFactoryBuilder

Apache Aries JPA container (92)
org/osgi/service/jpa/EntityManagerFactoryBuilder.class

OSGi Transaction Control JPA Resource Provider - Local Transactions (290)
org/osgi/service/jpa/EntityManagerFactoryBuilder.class

OSGi Transaction Control JPA Resource Provider - XA Transactions (291)
org/osgi/service/jpa/EntityManagerFactoryBuilder.class

We’ve also had no success in tracking down a compatible version of the 
defective bundle, looking at the maven repository there is a more recent 
version 2.2.1, but it also has an EntityManagerFactoryBuilder that is missing 
the getPersistenceProviderName():

https://mvnrepository.com/artifact/org.eclipse.persistence/javax.persistence

In summary it isn’t an option for us to configure only xa transactions or to 
omit eclipselink from our karaf jvm, so any insights that help us resolve this 
would be really appreciated!

Thanks

From: Jean-Baptiste Onofré <[email protected]>
Sent: Thursday, June 29, 2023 1:05 PM
To: [email protected]
Subject: Re: Autocommit is happening even within a transaction manager

Hi Ash,

What kind of datasource are you using ?

Regards
JB

On Wed, Jun 28, 2023 at 7:58 PM Ash Williams 
<[email protected]<mailto:[email protected]>> wrote:
Hi,

We have an issue where sql statements executed by hibernate are being 
immediately committed, despite the fact that the entity manager is managed by a 
(local) transaction. It's my understanding that hibernate and the transaction 
manager should together ensure that auto commit is disabled on the obtained 
connection. My environment is Karaf 4.4.3 on Java 8 and hibernate 5.6.7.

# Here is the persistence.xml file:

<persistence>
  <persistence-unit name="acme.pu" transaction-type="JTA" />
</persistence>

# Here is a self-contained class that demonstrates the problem:

import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.sql.DataSource;

import org.apache.commons.lang3.RandomStringUtils;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.jdbc.DataSourceFactory;
import org.osgi.service.jpa.EntityManagerFactoryBuilder;
import org.osgi.service.transaction.control.TransactionControl;
import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
import org.osgi.service.transaction.control.jpa.JPAEntityManagerProvider;
import org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory;

@Component(immediate = true)
public class AcmeTest {

   @Activate
   public AcmeTest(

      @Reference(target = "(osgi.unit.name<http://osgi.unit.name>=acme.pu)")
         EntityManagerFactoryBuilder emfb,

      @Reference(target = 
"(&(osgi.jdbc.driver.name<http://osgi.jdbc.driver.name>=oracle)(osgi.jdbc.driver.class=oracle.jdbc.OracleDriver))")
         DataSourceFactory dsf,

      @Reference(target = "(osgi.local.enabled=true)")
         JPAEntityManagerProviderFactory providerFactory,

      @Reference(target = "(osgi.local.enabled=true)")
         TransactionControl txControl

   ) throws IOException, SQLException {

      // create datasource from factory

      Properties dsfProps = new Properties();
      dsfProps.put("user", "xxx-withheld-xxx");
      dsfProps.put("password", "xxx-withheld-xxx");
      dsfProps.put("url", "xxx-withheld-xxx");

      DataSource datasource = dsf.createDataSource(dsfProps);

      // create jpa entity manager provider from datasource and pool props

      Map<String, Object> jpaProperties = new HashMap<>();
      jpaProperties.put("javax.persistence.dataSource", datasource);
      jpaProperties.put("hibernate.dialect", 
"org.hibernate.dialect.Oracle10gDialect");

      Map<String, Object> resourceProviderProperties = new HashMap<>();
      
resourceProviderProperties.put(JDBCConnectionProviderFactory.CONNECTION_POOLING_ENABLED,
 false);

      JPAEntityManagerProvider provider = providerFactory.getProviderFor(emfb, 
jpaProperties, resourceProviderProperties);

      // test it out by updating a test_column to a random string

      EntityManager entityManager = provider.getResource(txControl);
      txControl.required(() -> {

         String newValue = RandomStringUtils.random(10, true, false);

         Query query = entityManager.createNativeQuery("update test_table set 
test_column = ? where test_name = 'test'");
         query.setParameter(1, newValue);

         query.executeUpdate();

         // ***************************************************************
                              // CONNECTION HAS BEEN COMMITTED SINCE WE CAN SEE 
UPDATED VALUE OF
                              // TEST_COLUMN IN THE DATABASE WHILST WE ARE 
STILL IN THIS LAMBDA
         // ***************************************************************

         return null;

      });

   }

}

# This information about the transaction services running on the platform might 
be important:

admin@root()> bundle:services -p 281

pax-transx-tm-geronimo (281) provides:
--------------------------------------
objectClass = [org.osgi.service.cm.ManagedService]
service.bundleid = 281
service.id<http://service.id> = 335
service.pid = org.ops4j.pax.transx.tm.geronimo
service.scope = singleton
----
objectClass = [javax.transaction.TransactionManager, 
javax.transaction.TransactionSynchronizationRegistry, 
javax.transaction.UserTransaction, 
org.apache.geronimo.transaction.manager.RecoverableTransactionManage
r, org.springframework.transaction.PlatformTransactionManager]
service.bundleid = 281
service.id<http://service.id> = 360
service.scope = singleton
----
objectClass = [org.ops4j.pax.transx.tm.TransactionManager]
service.bundleid = 281
service.id<http://service.id> = 376
service.scope = singleton




admin@root()> bundle:services -p 298

OSGi Transaction Control JPA Resource Provider - Local Transactions (298) 
provides:
-----------------------------------------------------------------------------------
objectClass = 
[org.osgi.service.transaction.control.jpa.JPAEntityManagerProviderFactory]
osgi.local.enabled = true
service.bundleid = 298
service.id<http://service.id> = 312
service.scope = bundle
----
objectClass = [org.osgi.service.cm.ManagedServiceFactory]
service.bundleid = 298
service.id<http://service.id> = 313
service.pid = org.apache.aries.tx.control.jpa.local
service.scope = singleton

Thanks
Ash


[Image removed by sender. EDW Technology]<https://www.teamenergy.com/>
EDW Technology Ltd
3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ, United Kingdom
+44 (0)844 880 2489 | www.edwt.org<https://www.edwt.org>

Energy Auditing Agency Limited (TEAM) registered in England and Wales, number 
01916768. Registered office 3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ. 
This electronic message contains information which may be privileged or 
confidential. The information is intended for the use of the individual(s) or 
organisation named. If you are not the intended recipient please be aware that 
any disclosure, copying, distribution or use of the contents of this 
information is prohibited. If you have received this electronic message in 
error, please delete this e-mail from your system and notify us by replying to 
this email immediately.

________________________________

This email has been scanned for spam & viruses. If you believe this email 
should have been stopped by our filters, click 
here<https://portal.mailanyone.net/index.html#/outer/reportspam?token=dXNlcj1hd2lsbGlhbXNAZWR3dGVjaC5jb207dHM9MTY4ODA0MDMyMDt1dWlkPTY0OUQ3MzdCRDU0ODcyNTZDN0Q0NTU3MjY1Q0Q1Q0I3O3Rva2VuPWFlYmQ4ODEzMDk5YjljODQ3M2FiYWJjMTMzYTE2M2M2NDAwNDM1ZDM7>
 to report it.



[EDW Technology]<https://www.teamenergy.com/>
EDW Technology Ltd
3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ, United Kingdom
+44 (0)844 880 2489 | www.edwt.org<https://www.edwt.org>

Energy Auditing Agency Limited (TEAM) registered in England and Wales, number 
01916768. Registered office 3 Radian Court, Knowlhill, Milton Keynes MK5 8PJ. 
This electronic message contains information which may be privileged or 
confidential. The information is intended for the use of the individual(s) or 
organisation named. If you are not the intended recipient please be aware that 
any disclosure, copying, distribution or use of the contents of this 
information is prohibited. If you have received this electronic message in 
error, please delete this e-mail from your system and notify us by replying to 
this email immediately.

Reply via email to