Game 2.1. WebSocket No EntityManager associated with this thread

I am trying to implement WebSocket in Play 2.1. Framework along with JPA using Hibernate, and I get the following exception when I access the database from WebSocket:

java.lang.RuntimeException: No EntityManager bound to this thread. Try to annotate your action method with @play.db.jpa.Transactional at play.db.jpa.JPA.em(JPA.java:42) at model.operations.DistrictOperations.isOwner(DistrictOperations.java:15) at controllers.security.Secured.isOwnerOf(Secured.java:28) at controllers.DistrictCommunication.initWebSocket(DistrictCommunication.java:157) at Routes$$anonfun$routes$1$$anonfun$applyOrElse$20$$anonfun$apply$20.apply(routes_routing.scala:277) at Routes$$anonfun$routes$1$$anonfun$applyOrElse$20$$anonfun$apply$20.apply(routes_routing.scala:277) at play.core.j.JavaWebSocket$$anonfun$webSocketWrapper$1$$anonfun$apply$1.apply(JavaWebSocket.scala:20) at play.core.j.JavaWebSocket$$anonfun$webSocketWrapper$1$$anonfun$apply$1.apply(JavaWebSocket.scala:14) at play.core.server.netty.PlayDefaultUpstreamHandler.liftedTree1$1(PlayDefaultUpstreamHandler.scala:324) at play.core.server.netty.PlayDefaultUpstreamHandler.messageReceived(PlayDefaultUpstreamHandler.scala:322) at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565) at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:793) at org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:104) at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565) at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:793) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:455) at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:538) at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:437) at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:75) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:565) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:560) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255) at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:84) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.processSelectedKeys(AbstractNioWorker.java:472) at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:333) at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:35) at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:102) at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) at java.lang.Thread.run(Thread.java:680) 

Here is my code:

 @Transactional(readOnly = true) public static WebSocket<JsonNode> initWebSocket(final long id) { if (Secured.isOwnerOf(id)) { return new WebSocket<JsonNode>() { // Called when the Websocket Handshake is done. public void onReady(WebSocket.In<JsonNode> in, WebSocket.Out<JsonNode> out) { // For each event received on the socket, in.onMessage(new Callback<JsonNode>() { public void invoke(JsonNode event) { System.out.println(event); } }); // When the socket is closed. in.onClose(new Callback0() { public void invoke() { System.out.println("Disconnected"); } }); // Send a single 'Hello!' message ObjectNode on = Json.newObject(); on.put("greeting", "hello"); out.write(on); } }; }else{ return null; } 

secure isOwnerOf ():

 public static boolean isOwnerOf(Long district) { return DistrictOperations.isOwner(district, Context.current().request().username()); } 

and the DistrictOperations.isOwner () method:

 @Transactional(readOnly = true) public static boolean isOwner(long district, String login){ Query query = JPA.em().createQuery("SELECT d FROM District d WHERE d.id = :districtId"); District d = (District) query.setParameter("districtId", district).getSingleResult(); return d.getName().equals(login); } 

I am advised to add the @Transactional annotation that I have in my code, so my question is: is it possible to access the database through EntityManager from WebSocket? Because it seems to me that everything else except EntityManager works great here.

EDIT I even tried to use EntityManager inside a WebSocket, but I still have the same problem. So, perhaps a little reformulation - how should I work with the database using WebSocket and JPA? Is it possible to somehow use both together?

Thanks in advance.

+4
source share
1 answer

In playback mode, a WebSocket not an Action . The @Transactional annotation @Transactional not taken into account, since play.db.jpa.TransactionalAction only intercepts Action calls.

In your case, you need to manually place the code in a transaction with something like:

 boolean isOwnerOf = JPA.withTransaction(new play.libs.F.Function0<Boolean>{ public Boolean apply() throws Throwable { return Secured.isOwnerOf(id); } }) 

You will need to do the same if you need to access the database in your other web feed callbacks. These callbacks will be executed on other threads, and JPA.withTransaction() will take care of binding the EntityManager to these threads.

+8
source

Source: https://habr.com/ru/post/1480117/


All Articles