I'm trying to use a StatelessSession to do some bulk inserts in an OSGi environment (Karaf 4.0.7), but when I try to commit my transaction I get
be.ikan.lib.orm.base.exceptions.PersistenceBrokerException: org.hibernate.TransactionException: Cannot retrieve the TransactionManager OSGi service!
at be.ikan.lib.orm.hibernate.broker.HibernateStatelessPersistenceBrokerImpl.commitTransaction(HibernateStatelessPersistenceBrokerImpl.java:118)[79:be.ikan.lib.orm:7.0.0]
at be.ikan.scm4all.business.server.bs.pack.PackageServiceImpl.createLevelRequestFileRevisionAssociations(PackageServiceImpl.java:1412)[72:be.ikan.scm4all.daemons.server:5.8.0]
at be.ikan.scm4all.phases.core.level.LinkFileRevisionsPhase.execute(LinkFileRevisionsPhase.java:99)[72:be.ikan.scm4all.daemons.server:5.8.0]
at Proxy5a8c2944_a0d5_4e21_a1b7_3f30296f5993.execute(Unknown Source)[:]
at be.ikan.scm4all.phases.impl.DefaultPhaseExecutionImpl.execute(DefaultPhaseExecutionImpl.java:152)[114:be.ikan.scm4all.daemons.shared:5.8.0]
at be.ikan.scm4all.daemons.server.monitor.MonitorThread.run(MonitorThread.java:231)[72:be.ikan.scm4all.daemons.server:5.8.0]
Caused by: org.hibernate.TransactionException: Cannot retrieve the TransactionManager OSGi service!
at org.hibernate.osgi.OsgiJtaPlatform.retrieveTransactionManager(OsgiJtaPlatform.java:51)[62:org.hibernate.osgi:5.2.17.Final]
at org.hibernate.osgi.OsgiJtaPlatform.getCurrentStatus(OsgiJtaPlatform.java:98)[62:org.hibernate.osgi:5.2.17.Final]
at org.hibernate.internal.StatelessSessionImpl.flushBeforeTransactionCompletion(StatelessSessionImpl.java:667)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.internal.StatelessSessionImpl.beforeTransactionCompletion(StatelessSessionImpl.java:644)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:156)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231)[60:org.hibernate.core:5.2.17.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)[60:org.hibernate.core:5.2.17.Final]
at be.ikan.lib.orm.hibernate.broker.HibernateStatelessPersistenceBrokerImpl.commitTransaction(HibernateStatelessPersistenceBrokerImpl.java:114)[79:be.ikan.lib.orm:7.0.0]
... 5 more
Caused by: org.hibernate.TransactionException: Cannot retrieve the TransactionManager OSGi service!
at org.hibernate.osgi.OsgiJtaPlatform.retrieveTransactionManager(OsgiJtaPlatform.java:46)[62:org.hibernate.osgi:5.2.17.Final]
I don't use JTA for managing my transactions, I set hibernate.transaction.coordinator_class=jdbc. The code that uses a regular Sesssion runs fine. There's another portion of the application that runs in a non-OSGi environment, and there the StatelessSession works fine.
I tracked it down into the Hibernate source and found in org.hibernate.internal.StatelessSessionImpl :
@Override
public void flushBeforeTransactionCompletion() {
boolean flush = false;
try {
flush = (
!isClosed()
&& !isFlushModeNever()
&& !JtaStatusHelper.isRollback(
getJtaPlatform().getCurrentStatus()
) );
}
catch (SystemException se) {
throw new HibernateException( "could not determine transaction status in beforeCompletion()", se );
}
if ( flush ) {
managedFlush();
}
}
Since the session isn't closed, and StatelessSessionImpl.isFlushModeNever() always returns false, the method getJtaPlatform() always gets called, which ultimately fails because it can find a JtaPlatform (org.hibernate.osgi.OsgiJtaPlatform), but it isn't configured (because I don't use it).
So does that mean you can't use a StatelessSession without configuring JTA ?
I'm using Hibernate 5.2.17. This approach worked fine in Hibernate 4.3.7 by the way, but then there was no hibernate-osgi bundle, and it seems the StatelessSessionImpl class has undergone some significant changes.
After some further investigation, I managed to get it working by installing the Karaf feature "transaction". In the karaf console, I executed feature:install transaction
. This installs an OSGi Transaction Manager (provided by Apache Aries), which registers a Service implementation for javax.transaction.TransactionManager, which allows the org.hibernate.osgi.OsgiJtaPlatform class to locate it and gets rid of the above Exception.
The code seems to work after that : transactions are committed without problems and the data is persisted.
But I'm still left with the question : does the StatelessSession use JTA Transactions or not ?
In the non-OSGi portion of the application, which runs in Tomcat, I found in the debug logs
2018-08-29 13:29:00,615 [localhost-startStop-1] DEBUG JtaPlatformInitiator - No JtaPlatform was specified, checking resolver
2018-08-29 13:29:00,617 [localhost-startStop-1] DEBUG JtaPlatformResolverInitiator - No JtaPlatformResolver was specified, using default [org.hibernate.engine.transaction.jta.platform.internal.StandardJtaPlatformResolver]
2018-08-29 13:29:00,629 [localhost-startStop-1] DEBUG StandardJtaPlatformResolver - Could not resolve JtaPlatform, using default [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
So there Hibernate uses org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform.
In the karaf log, I found the properties with which the SessionFactory is instantiated :
2018-08-29 14:45:48,897 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Building session factory
2018-08-29 14:45:48,936 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Session factory constructed with filter configurations : {}
2018-08-29 14:45:48,937 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Instantiating session factory with properties: {<a lot of properties>, hibernate.transaction.jta.platform=org.hibernate.osgi.OsgiJtaPlatform@7d6ea302, <more properties>}
2018-08-29 14:45:48,969 | DEBUG | e: pid=[server]) | SessionFactoryImpl | 72 - org.jboss.logging.jboss-logging - 3.3.1.Final | Instantiated session factory
I tried setting the jta platform to NoJtaPlatform by adding to hibernate.properties
hibernate.transaction.jta.platform=org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform
But this had no effect : it still logged that the session factory was created using OsgiJtaPlatform.
If I can somehow configure Hibernate so that it uses the NoJtaPlatform in Karaf, then I think I wouldn't need the extra "transaction" feature. It would also convince me that the application only uses JDBC transactions, and not JTA.