glassfish
  1. glassfish
  2. GLASSFISH-20371

Can't listen to JMS Queue from a WebSocket

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Critical Critical
    • Resolution: Duplicate
    • Affects Version/s: 4.0_b83
    • Fix Version/s: future release
    • Component/s: cdi
    • Labels:
      None

      Description

      It should be possible to connect a WebSocket and a JMS queue using standards. The usecase is based on the idea where each websocket session will be a subscriber to a Topic. In this example specifically, code is based on a WebSocket session consuming a Queue.

      It is possible to inject a JMSContext inside a WebSocket using @Inject at constructor [1], but whenever I try to inject a Queue/Topic, it does not get injected using @Resource [2].

      Also tried to use JMS 1.1 code (creating a InitialContext, doing lookup on ConnectionFactory, etc), it dit not work.

      Most of the time, I get this error [3].

      MyWebSocket.java
      @Named // with @Named or without, nothing from CDI works as it should
      @ServerEndpoint("/path")
      public class MyWebSocket implements MessageListener {
        // @Inject at field level does not work
        private JMSContext jmsContext;
      
        @Resource(mappedName = "jms/myQueue") // [2] jms queue/topic does not get injected
        private Queue queue;
      
        @Inject // [1] at constructor, it works
        public MyWebSocket(JMSContext jmsc) {
          this.jmsContext = jmsc;
          ... // code to create a MessageListener
         jmsContext.createConsumer(queue).setMessageListener(this);
        }
      
        public void onMessage(Message m) {
          webSocketSession.getAsyncRemote().sendText(m.getBody(String.class));
        }
      
      }
      

        Activity

        Hide
        Nigel Deakin added a comment - - edited

        That matches my own experiments. Your call to context.createConsumer was successful, which suggests that an injected JMSContext can be used in the @OnOpen callback. However you should be aware that as an injected JMSContext has @RequestScoped (when there is no transaction) any object created from it will become invalid when the request ends. So the JMSConsumer you create from it won't be usable after then.

        However when I invoked your @OnMessage callback (modified to catch exceptions) I got a Weld error:

        SEVERE:   org.jboss.weld.context.ContextNotActiveException: 
        WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped 
        

        which suggests there is a restriction in using an injected JMSContext in the @OnMessage callback. That's an open issue.

        However, as you saw, you also hit the restriction that you can't set a MessageListener in a Java EE environment (except the ACC). This restriction is not new and was in Java EE 6.

        There is no restriction on consuming messages synchronously (using JMSConsumer.receive()), or in sending messages. But if you want to consume messages asynchronously you're expected to use a MDB.

        I suggest moving discussion of your application design to email.

        Show
        Nigel Deakin added a comment - - edited That matches my own experiments. Your call to context.createConsumer was successful, which suggests that an injected JMSContext can be used in the @OnOpen callback. However you should be aware that as an injected JMSContext has @RequestScoped (when there is no transaction) any object created from it will become invalid when the request ends. So the JMSConsumer you create from it won't be usable after then. However when I invoked your @OnMessage callback (modified to catch exceptions) I got a Weld error: SEVERE: org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped which suggests there is a restriction in using an injected JMSContext in the @OnMessage callback. That's an open issue. However, as you saw, you also hit the restriction that you can't set a MessageListener in a Java EE environment (except the ACC). This restriction is not new and was in Java EE 6. There is no restriction on consuming messages synchronously (using JMSConsumer.receive()) , or in sending messages. But if you want to consume messages asynchronously you're expected to use a MDB. I suggest moving discussion of your application design to email.
        Hide
        Bruno Borges added a comment - - edited

        I managed to make this work using CDI events. Still, some things had to be changed:

        1. It is impossible, as I understand from the spec, to connect WebSockets and JMS directly.
        2. To send an incoming message from a WebSocket client to a JMS queue, I used a @Stateless session bean
          There's still a bug in here, because it was not possible to @Inject the SB the normal way. Had to use constructor-injected parameter.
        3. SessionBean does use JMS 2 the way it is specified, @Inject JMSContext and @Resource Queue.
        4. @MessageDriven bean produces a CDI event with the JMS payload
        5. The WebSocket server endpoint @Observes for CDI event with the payload. Then payload is sent to all WebSocket sessions

        The code is available here

        Show
        Bruno Borges added a comment - - edited I managed to make this work using CDI events. Still, some things had to be changed: It is impossible, as I understand from the spec, to connect WebSockets and JMS directly. To send an incoming message from a WebSocket client to a JMS queue, I used a @Stateless session bean There's still a bug in here, because it was not possible to @Inject the SB the normal way. Had to use constructor-injected parameter. SessionBean does use JMS 2 the way it is specified, @Inject JMSContext and @Resource Queue. @MessageDriven bean produces a CDI event with the JMS payload The WebSocket server endpoint @Observes for CDI event with the payload. Then payload is sent to all WebSocket sessions The code is available here
        Hide
        Bruno Borges added a comment -

        Although I'm happy that such integration is possible, I wonder if this could be simplified by JMS_SPEC-100

        Show
        Bruno Borges added a comment - Although I'm happy that such integration is possible, I wonder if this could be simplified by JMS_SPEC-100
        Hide
        Bruno Borges added a comment -

        Created two separate bugs that were found due to this issue:

        Show
        Bruno Borges added a comment - Created two separate bugs that were found due to this issue: GLASSFISH-20467 GLASSFISH-20468
        Hide
        jjsnyder83 added a comment -
        Show
        jjsnyder83 added a comment - Duplicate of https://java.net/jira/browse/JMS_SPEC-121

          People

          • Assignee:
            jjsnyder83
            Reporter:
            Bruno Borges
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: