No matter how I rewrite the query bit for the EventListenerProvider below, I cannot seem to make it work. I am attempting to react to group creation events by adding new subgroups to every newly created group.
The language used here is Scala, but I hope it is understandable.
class XylemEventListenerProvider(session: KeycloakSession)
extends EventListenerProvider {
val groupIdPatt = "groups/(.+)".r // Simplified regex here.
override def onEvent(event: Event) = () // Not interested in this
override def onEvent(
adminEvent: AdminEvent,
includeRepresentation: Boolean
) =
(adminEvent.getOperationType() ,adminEvent.getResourcePath()) match
case (OperationType.CREATE, groupIdPatt(id)) =>
session.getTransactionManager().enlist(new AbstractKeycloakTransaction {
protected def commitImpl(): Unit = {
try
val realm = session.realms().getRealm(adminEvent.getRealmId())
val groups = session.groups
val group = groups.getGroupById(id, realm)
List("subgroup-1", "subgroup-2").foreach { subgroup =>
groups.createGroup(realm, subgroup, group)
s"The `$subgroup` subgroup for the newly created group was created successfully"
}
catch
case e =>
e.printStackTrace()
throw e
}
protected def rollbackImpl(): Unit = ()
})
case _ => ()
override def close() = ()
}
The error is:
org.keycloak.models.ModelException: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.keycloak.connections.jpa.PersistenceExceptionConverter.convert(PersistenceExceptionConverter.java:84)
at org.keycloak.connections.jpa.PersistenceExceptionConverter.invoke(PersistenceExceptionConverter.java:62)
at com.sun.proxy.$Proxy86.flush(Unknown Source)
at org.keycloak.models.jpa.JpaRealmProvider.createGroup(JpaRealmProvider.java:620)
at org.keycloak.storage.GroupStorageManager.createGroup(GroupStorageManager.java:109)
at org.keycloak.models.cache.infinispan.RealmCacheSession.createGroup(RealmCacheSession.java:1052)
at org.keycloak.models.RealmProvider.createGroup(RealmProvider.java:394)
at ca.growwithtreehouse.keycloak.provider.XylemEventListenerProvider.ca$growwithtreehouse$keycloak$provider$XylemEventListenerProvider$$anon$1$$_$commitImpl$$anonfun$1(XylemEventListenerProvider.scala:58)
at scala.collection.immutable.List.foreach(List.scala:333)
at ca.growwithtreehouse.keycloak.provider.XylemEventListenerProvider$$anon$1.commitImpl(XylemEventListenerProvider.scala:59)
at org.keycloak.models.AbstractKeycloakTransaction.commit(AbstractKeycloakTransaction.java:48)
at org.keycloak.services.DefaultKeycloakTransactionManager.commit(DefaultKeycloakTransactionManager.java:136)
at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.close(QuarkusRequestFilter.java:129)
at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$configureEndHandler$2(QuarkusRequestFilter.java:95)
at io.vertx.ext.web.impl.RoutingContextImpl.lambda$null$0(RoutingContextImpl.java:545)
at io.vertx.ext.web.impl.SparseArray.forEachInReverseOrder(SparseArray.java:40)
at io.vertx.ext.web.impl.RoutingContextImpl.lambda$getHeadersEndHandlers$1(RoutingContextImpl.java:545)
at io.vertx.core.http.impl.Http1xServerResponse.prepareHeaders(Http1xServerResponse.java:707)
at io.vertx.core.http.impl.Http1xServerResponse.end(Http1xServerResponse.java:411)
at io.vertx.core.http.impl.Http1xServerResponse.end(Http1xServerResponse.java:391)
at io.vertx.core.http.impl.Http1xServerResponse.end(Http1xServerResponse.java:460)
at io.quarkus.resteasy.runtime.standalone.VertxBlockingOutput.write(VertxBlockingOutput.java:71)
at io.quarkus.resteasy.runtime.standalone.VertxHttpResponse.writeBlocking(VertxHttpResponse.java:172)
at io.quarkus.resteasy.runtime.standalone.VertxOutputStream.close(VertxOutputStream.java:126)
at io.quarkus.resteasy.runtime.standalone.VertxHttpResponse.finish(VertxHttpResponse.java:145)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:170)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:71)
at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:445)
at org.hibernate.internal.SessionImpl.checkTransactionNeededForUpdateOperation(SessionImpl.java:3478)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1394)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1389)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.keycloak.connections.jpa.PersistenceExceptionConverter.invoke(PersistenceExceptionConverter.java:60)
... 50 more
If I use session.getTransactionManager().begin()
I will get a different error informing that “A transaction is already active” or something similar to that.