Can you use a Hibernate 5.2 StatelessSession in an OSGi environment (like Karaf) without the use of JTA?


#1

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 the OsgiJtaPlatform can’t find a TransactionManager.

When I install the Karaf feature “transaction”, which installs an OSGi Transaction Manager (provided by Apache Aries), the Exception is no longer thrown and everything is committed fine. However, it seems silly that I have to install a JTA component for using StatelessSession, while I don’t use JTA Transactions.

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.

Is there a way to make Hibernate use the NoJtaPlatform when it’s running in an OSGi container ?

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.


#2

Maybe @brmeyer can help you find the right answer. He knows the OSGI part better than anyone else.


#3

Sorry for the delayed response! @frank.sjegers, sounds like a legitimate bug in hibernate-osgi. If you haven’t already, could you create a JIRA ticket with these details and assign it to me?